from google.appengine.ext import db

from gaev import BaseModel 
from gaev.actions import cart 
import gaev

class Error(Exception):
	pass
class MissingModelError(Error):
	pass


def get(name):
	#all model names start with uppercase letter
	if not name[0].isupper():
		 raise MissingModelError(name)
	try:
		return globals()[name]
	except KeyError:
		raise MissingModelError(name)
	
def get_actions():
	return ['root', 'cart_analyzer']
def get_action(name):
	if name == 'root':
		from gaev.actions import auxiliary as auxiliary_actions
		return auxiliary_actions.RootAction()
	elif name == 'cart_analyzer':
		from data.my_actions import ProverResultCartAnalyzerAction
		return ProverResultCartAnalyzerAction()

gaev.actions.register_action_getter(None, lambda x, name:get_action(name), lambda x:get_actions(), False)


class Division(BaseModel):
	short = db.StringProperty(required=True, verbose_name='Short name')
	name = db.StringProperty(verbose_name='Full name')
	description = db.TextProperty()

	_human_key = 'short'
	_ordered_properties = [short, name]
cart.register_model(Division)

class AxiomFamily(BaseModel):
	division = db.ReferenceProperty(Division,  collection_name='families')
	short = db.StringProperty(required=True)
	name = db.StringProperty()

	_human_key = 'short'
	_ordered_properties = [short, division, name]
Division._inner_property=AxiomFamily.division
cart.register_model(AxiomFamily)

class AxiomSet(BaseModel):
	family = db.ReferenceProperty(AxiomFamily)
	short = db.StringProperty(required=True)
	name = db.StringProperty()

	_human_key = 'short'
	_ordered_properties = [short, family, name]

	def get_details_sections(self):
		from gaev.actions.model.details import ReferringEntitiesSection
		res=super(AxiomSet, self).get_details_sections()
		res.append(ReferringEntitiesSection(Problem.axioms))
		return res
AxiomFamily._inner_property=AxiomSet.family
cart.register_model(AxiomSet)

class ProblemStatus(BaseModel):
	name = db.StringProperty(required=True)
	abbr = db.StringProperty()
	theorem = db.BooleanProperty()
	unknown = db.BooleanProperty()

	_human_key = 'name'
	_ordered_properties = [name, abbr]

class Problem(BaseModel):
	division = db.ReferenceProperty(Division)
	short = db.StringProperty(required=True)
	name = db.StringProperty()
	status = db.ReferenceProperty(ProblemStatus)
	axioms = db.ListProperty(db.Key)
	axioms._target=AxiomSet
	
	_human_key = 'short'
	_ordered_properties = [short, division, name, status]
	
	def get_details_sections(self):
		from data.my_actions import ProblemSolutionsSection 
		res=super(Problem, self).get_details_sections()
		res.append(ProblemSolutionsSection())
		return res
ProblemStatus._inner_property=Problem.status
cart.register_model(Problem)
	
class ProblemGroup(BaseModel):
	name = db.StringProperty()
	problems = db.ListProperty(db.Key)
	problems._target=Problem

	_human_key = 'name'
	_ordered_properties = [name]
cart.register_model(ProblemGroup)
	
	
class Prover(BaseModel):
	name = db.StringProperty(required=True)
	added = db.DateTimeProperty(auto_now_add=True)

	_human_key = 'name'
	_ordered_properties = [name]
cart.register_model(Prover)

class ProverVersion(BaseModel):
	prover = db.ReferenceProperty(Prover, required=True)
	short = db.StringProperty(required=True)
	version = db.StringProperty()
	hash = db.StringProperty()
	added = db.DateTimeProperty(auto_now_add=True)
	_ordered_properties = [prover, short, version, hash]
	_human_key = 'short'
cart.register_model(ProverVersion)

class OutputFormat(BaseModel):
	name = db.StringProperty(required=True)
	_human_key = 'name'

class ProverInstance(BaseModel):
	engine = db.ReferenceProperty(ProverVersion, required=True)
	short = db.StringProperty(required=True)
	outputFormat = db.ReferenceProperty(OutputFormat)
	commandLine = db.StringProperty()
	timeLimit = db.IntegerProperty()
	added = db.DateTimeProperty(auto_now_add=True)

	_human_key = 'short'
	_ordered_properties = [engine, short, timeLimit, outputFormat, commandLine]
	
	def get_details_sections(self):
		from data.my_actions import ProverResultsSection 
		res=super(ProverInstance, self).get_details_sections()
		res.append(ProverResultsSection())
		return res
cart.register_model(ProverInstance)



class CPUFamily(BaseModel):
	name = db.StringProperty()
	short = db.StringProperty(required=True)
	
	_model_caption='CPU families'
	_human_key = 'short'
	_ordered_properties = [short, name]

class OS(BaseModel):
	name = db.StringProperty()
	short = db.StringProperty(required=True)
	version = db.StringProperty()
	arch = db.StringProperty()
	
	_model_caption='Operating systems'
	_human_key = 'short'
	_ordered_properties = [short, name]

class Computer(BaseModel):
	short = db.StringProperty(required=True)
	cpu = db.ReferenceProperty(CPUFamily)
	os = db.ReferenceProperty(OS)
	name = db.StringProperty()
	cpuFreq = db.IntegerProperty()
	ram = db.IntegerProperty()
	benchCoef = db.FloatProperty()
	added = db.DateTimeProperty(auto_now_add=True)

	_human_key = 'short'
	_ordered_properties = [short, name]


class ResultType(BaseModel):
	name = db.StringProperty(required=True)
	proved = db.BooleanProperty()
	refuted = db.BooleanProperty()
	timeOut = db.BooleanProperty()
	
	_human_key = 'name'
	_ordered_properties = [name]

class ResultEvaluation(BaseModel):
	problemStatus = db.ReferenceProperty(ProblemStatus, required=True)
	resultType = db.ReferenceProperty(ResultType, required=True)
	ok = db.BooleanProperty()
	wrong = db.BooleanProperty()
	discovery = db.BooleanProperty()
	fail = db.BooleanProperty()
	
	_ordered_properties = [problemStatus, resultType]

class Result(BaseModel):
	problem = db.ReferenceProperty(Problem, required=True)
	prover = db.ReferenceProperty(ProverInstance, required=True)
	resultType = db.ReferenceProperty(ResultType, required=True)
	computer = db.ReferenceProperty(Computer)
	time = db.FloatProperty()
	memoryUsage = db.IntegerProperty()
	added = db.DateTimeProperty(auto_now_add=True)
	
	_ordered_properties = [problem, prover, resultType, computer, time, memoryUsage]

	def get_caption(self):
		return "(%s, %s -> %s)" % (self.problem.get_caption(), self.prover.get_caption(), self.resultType.get_caption())
Problem._inner_property=Result.problem


class Proof(BaseModel):
	problem = db.ReferenceProperty(Problem, required=True)
	origin = db.ReferenceProperty(Result)
	prover = db.ReferenceProperty(ProverInstance)
	format = db.ReferenceProperty(OutputFormat)
	text = db.TextProperty()
	added = db.DateTimeProperty(auto_now_add=True)

	_ordered_properties = [problem, origin, prover, format, text]
	
class PublishedFile(BaseModel):
	name = db.StringProperty(required=True)
	title = db.StringProperty()
	content = db.TextProperty()
	added = db.DateTimeProperty(auto_now_add=True)
	
	_human_key = 'name'
	_ordered_properties = [name, title, content]

class SavedAnalyses(BaseModel):
	name = db.StringProperty(required=True)
	problems = db.ListProperty(db.Key)
	problems._target=Problem
	provers = db.ListProperty(db.Key)
	provers._target=ProverInstance

	_human_key = 'name'
	_ordered_properties = [name]
